﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Configuration;
using System.Diagnostics;
using Engine.Dtd.Configuration;

namespace Engine.Dtd.Schema {
    internal class EntityResolver {
        private EntityCatalogSection catalog;
        private PreferedIdentifier preferedIdentifier;
        private UrlResolver urlResolver;

        public EntityResolver() {
            catalog = ConfigurationManager.GetSection("catalog") as EntityCatalogSection;
            if (catalog != null)
                preferedIdentifier = (PreferedIdentifier)Enum.Parse(typeof(PreferedIdentifier), catalog.Prefer, true);
            urlResolver = new UrlResolver();
            }

        public Uri BaseUrl { get; set; }

        public TextReader Resolve(string publicId, string system) {
            if (catalog != null)
                switch (preferedIdentifier) {
                    case PreferedIdentifier.Public:
                        if (!string.IsNullOrWhiteSpace(publicId)) {
                            PublicElement element = catalog.PublicEntities[publicId];
                            if (element != null)
                                system = element.Url;
                            }
                        break;
                    case PreferedIdentifier.System:
                        if (string.IsNullOrWhiteSpace(system) && !string.IsNullOrWhiteSpace(publicId)) {
                            PublicElement element = catalog.PublicEntities[publicId];
                            if (element != null)
                                system = element.Url;
                            }
                        break;
                    default:
                        throw new InvalidOperationException("Unknown the prefered identifier.");
                    }
            if (string.IsNullOrWhiteSpace(system)) {
                if (string.IsNullOrWhiteSpace(publicId))
                    throw new DtdException("Could not resolve the external entity.");
                else
                    throw new DtdException(string.Format("Could not resolve an external entity '{0}'.", publicId));
                }
            Debug.Assert(BaseUrl != null);
            try {
                return urlResolver.GetEntity(UrlResolver.ResolveUrl(BaseUrl, system));
                }
            catch (Exception e) {
                throw new DtdException(string.Format("Could not resolve the external entity. {0}", UrlResolver.ResolveUrl(BaseUrl, system)), e);
                }
            }
        }
    }
